#!/usr/bin/env python
# encoding: utf-8
'''
TpScheduler -- TPlus task scheduler

TpScheduler is a class for scheduling monitoring task.

It defines classes_and_methods

@author:     Anson Chan

@copyright:  2016 Xerland Co. Ltd. All rights reserved.

@contact:    anson_chan@xerland.com
@deffield    updated: Updated
'''
import sched
import time
from Adb.PowerMonitor import PowerMonitor
from Adb.RtdMonitor import RtdMonitor
from Utils.SysConstants import TPLUS_MACH_POWER_SAMPLE_INTERVAL,\
    TPLUS_MACH_RTD_SAMPLE_INTERVAL, TPLUS_POLLING_DEFAULT_INTERVAL,\
    SERVERAPI_CONFIGSERVICE, TPLUS_TASK_DEFAULT_INTERVAL, LOGGER
import threading
import pythoncom
import sys
import traceback
import datetime
from Queue import Queue
import Queue
from Utils.TopicFormater import TopicFormater

#pythoncom.CoInitialize()

class TpScheduler():
    '''
    classdocs
    '''


    def __init__(self, isthread = False):
        '''
        Constructor
        '''
        self.mMachPowerStateList = []
        self.mMachRtdUpdateList = []
        self.mPowerMonitor = PowerMonitor()
        self.mRtdMonitor = RtdMonitor()
        self.mSched = sched.scheduler(time.time, time.sleep)
        self.mPowerMonitorCb = None
        self.mRtdMonitorCb = None
#        self.mRunThread = threading.Thread(target=self.mSched.run)
        self.ifStop = False
#        self.loop()
        self.mUpStreamQ = None
        self.mDownStreamQ = None
        self.mPeriodPubList = []  #list of (interval,topic, task)
        self.mSubList = [] #list of (topic,task)
        self.mTimeoutList = []
        self.syncTimeoutList()
        self.setTimeInterval()
        self.isthread = isthread
        if self.isthread:
            self.mSchedThread = threading.Thread(target=self.doSchedule)
        
    def setTimeInterval(self):
        self.mTimeoutInterval = SERVERAPI_CONFIGSERVICE.getValue("schedule_interval")
        if self.mTimeoutInterval:
            self.mTimeoutInterval = float(self.mTimeoutInterval)
        if not self.mTimeoutInterval or self.mTimeoutInterval>1:
            self.mTimeoutInterval = TPLUS_POLLING_DEFAULT_INTERVAL
        self.mStepSecondFactor = 1/self.mTimeoutInterval
        self.mMicrosecondFactor = 1000000*self.mTimeoutInterval
        
    def syncTimeoutList(self):
        self.mTimeoutList = []
        for interval,topic,task in self.mPeriodPubList:
            self.mTimeoutList.append(interval)
            
    def setTimeoutListDecSeconds(self, sec):
        for i in range(0,len(self.mTimeoutList)):
            self.mTimeoutList[i] -= sec*10
    
    def setTimeoutListDec(self):
        for i in range(0,len(self.mTimeoutList)):
            self.mTimeoutList[i] -= 1        
        
    def setUpStreamQ(self, q):
        self.mUpStreamQ = q
        
    def setDownStreamQ(self, q):
        self.mDownStreamQ = q
        
    def pubTask(self, interval, topic, task):
        if interval<=0:
            interval = TPLUS_TASK_DEFAULT_INTERVAL
        self.mPeriodPubList.append((interval*self.mStepSecondFactor, topic, task))
        self.syncTimeoutList()
        
    def subTask(self, topic, task):
        self.mSubList.append((topic, task))
        
    def doSubTask(self, topic, payload):
        print "topic is ",topic
        for tp,task in self.mSubList:
            print "tp is ",tp
            print "split 0 is ", topic.split("@")[0]
            print "topic len is",len(topic)
            print "tp len is ", len(tp)
            if TopicFormater.isEqual(topic, tp):
                print "match topic is:", tp
                resultList = task(payload)
                if resultList:
                    self.mUpStreamQ.put((topic,resultList))
                    print('put Queue',(topic,resultList))
                    
    def doPubTask(self):
        for i in range(0,len(self.mTimeoutList)):
            if self.mTimeoutList[i] < 0:
                self.mTimeoutList[i] = self.mPeriodPubList[i][0]
                resultList = self.mPeriodPubList[i][2]()
                self.mUpStreamQ.put((self.mPeriodPubList[i][1],resultList))
                
    def doSchedule(self):
        while not self.ifStop:
            try:
                msg = self.mDownStreamQ.get(timeout=self.mTimeoutInterval)
                print "do getqQ"
                if msg:
                    t1 = datetime.datetime.now()
                    topic,payload = msg
                    print "before doSubTask","topic ",topic,"payload ",payload
                    self.doSubTask(topic, payload)
                    t2 = datetime.datetime.now()
                    self.setTimeoutListDecSeconds((t2-t1).microseconds/100000)
            except Queue.Empty:
                
                self.setTimeoutListDec()
                self.doPubTask()
                continue
            except Exception,e:
                traceback.print_exc()
                LOGGER.error("Down stream Queue handling error!")
                
    def start(self):
        if self.isthread:
            self.mSchedThread.start()    
            
    def stop(self):  
        self.ifStop = True  
        if self.isthread:
            self.mSchedThread.join()
        
    
if __name__ == '__main__':
    import json
    from Utils.JsonHelper import toJson
#    from win32com.client import Dispatch
    def doPowerMonitorCb(powerStateList):
        print "doPowerMonitorCb"
        if powerStateList:
            print json.dumps(powerStateList, default=toJson)
        print powerStateList
#    def doRtdMonitorCb(rtdStateList):
#        print "doRtdMonitorCb"
#        if rtdStateList:
#            print json.dumps(rtdStateList, default=toJson)
    upStreamQ = Queue.Queue()
    downStreamQ = Queue.Queue()
    mTpSched = TpScheduler()
    mTpSched.setUpStreamQ(upStreamQ)
    mTpSched.setDownStreamQ(downStreamQ)
    powerMonitor = PowerMonitor()
    rtdMonitor = RtdMonitor()
    mTpSched.subTask(TopicFormater.getSubSelfPeerX("/powerstate"), powerMonitor.getMachPowerState)#SERVERAPI_CONFIGSERVICE.getValue("mq_power_subscription_request")
    mTpSched.subTask(TopicFormater.getSubSelfPeerX("/rtd"), rtdMonitor.getHistory)   #SERVERAPI_CONFIGSERVICE.getValue("mq_rtd_subscription_request")
    mTpSched.pubTask(6, TopicFormater.getPubSelf("/powerstate/update"), powerMonitor.getMachPowerState)   #SERVERAPI_CONFIGSERVICE.getValue("mq_power_subscription_update")
    
    mTpSched.pubTask(6, TopicFormater.getPubSelf("/rtd/update"), rtdMonitor.getUpdate)    #SERVERAPI_CONFIGSERVICE.getValue("mq_rtd_subscription_update")

#    mTpSched.setPowerMonitorCb(doPowerMonitorCb)
#    mTpSched.setRtdMonitorCb(doRtdMonitorCb)
#    pythoncom.CoInitialize()

#    mTpSched.doSchedule()
    
    while True:
        time.sleep(1)
    